package org.fmi.lje.graphics.model;

import java.awt.Color;
import java.awt.FontMetrics;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;

public abstract class Clazz extends Shape {

	protected Class<?> target;
	protected static final int PADDING = 10;

	protected Clazz() {
		super(0, 0, 0, 0, null);
	}

	public void setTarget(Class<?> target) {
		this.target = target;
	}

	public void setParent(Shape parent) {
		super.setParent(parent);
	}

	public int getX() {
		return getLayoutManager().getPosition(this).getX();
	}

	public int getY() {
		return getLayoutManager().getPosition(this).getY();
	}

	@Override
	public int getHeight() {
		FontMetrics fm = getGraphics().getFontMetrics();

		int h = fm.getAscent();
		int height = h;

		height += target.getConstructors().length * h;
		height += target.getFields().length * h;
		height += target.getMethods().length * h;
		height += 3 * h;
		height += 6 * PADDING;

		return height;
	}

	@Override
	public int getWidth() {
		FontMetrics fm = getGraphics().getFontMetrics();
		int width = fm.stringWidth(target.getCanonicalName());

		for (Constructor<?> constructor : target.getConstructors()) {
			if (fm.stringWidth(constructor.toGenericString()) > width) {
				width = fm.stringWidth(constructor.toGenericString());
			}
		}

		for (Field field : target.getFields()) {
			if (fm.stringWidth(field.toGenericString()) > width) {
				width = fm.stringWidth(field.toGenericString());
			}
		}

		for (Method method : target.getMethods()) {
			if (fm.stringWidth(method.toGenericString()) > width) {
				width = fm.stringWidth(method.toGenericString());
			}
		}

		width += 4 * PADDING;

		return width;
	}

	@Override
	public void draw() {
		getGraphics().setFont(getFont());
		getGraphics().setColor(Color.black);

		FontMetrics fm = getGraphics().getFontMetrics();

		int h = fm.getAscent();
		int x = getX();
		int y = getY() + h + PADDING;

		getGraphics().drawString(target.getCanonicalName(), x + PADDING, y);
		y += h + PADDING;

		getGraphics().drawLine(x, y, x + getWidth(), y);
		y += h + PADDING;

		for (Constructor<?> constructor : target.getConstructors()) {
			getGraphics().drawString(constructor.toGenericString(), x + PADDING, y);
			y += h;
		}

		getGraphics().drawLine(x, y, x + getWidth(), y);
		y += h + PADDING;

		for (Field field : target.getFields()) {
			getGraphics().drawString(field.toGenericString(), x + PADDING, y);
			y += h;
		}

		getGraphics().drawLine(x, y, x + getWidth(), y);
		y += h + PADDING;

		for (Method method : target.getMethods()) {
			getGraphics().drawString(method.toGenericString(), x + PADDING, y);
			y += h;
		}

		getGraphics().drawRect(getX(), getY(), getWidth(), getHeight());
	}
	
	@Override
	public String toString() {
		return target != null ? target.toString() : "null";
	}

	public abstract Collection<? extends Clazz> getSuperClassHierarchy();

	public abstract Collection<? extends Clazz> getSubclassHierarchy();
	
	public abstract Collection<? extends Relationship> getSuperclasses();
	
	public abstract Collection<? extends Relationship> getSubclasses();

	public abstract Collection<? extends Relationship> getAssociations();
}
